package cn.xinfei.xdecision.data.core.frame.executors.collect.handler;

import cn.xinfei.xdecision.common.model.datax.datamanage.v2.Variable;
import cn.xinfei.xdecision.common.model.datax.enums.VariableEnum;
import cn.xinfei.xdecision.common.service.datax.datamanage.v2.VariableParamService;
import cn.xinfei.xdecision.common.service.datax.datamanage.v2.VariableService;
import cn.xinfei.xdecision.data.core.cache.VarMetaDataCache;
import cn.xinfei.xdecision.data.core.cache.VarParamsCache;
import cn.xinfei.xdecision.data.core.frame.executors.VarContext;
import cn.xinfei.xdecision.data.core.frame.executors.collect.VarHandler;
import cn.xinfei.xdecision.data.core.vo.VarCollectAwareVO;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


@Service
@Slf4j
public class VarDeriveDependParamHandler implements VarHandler<VarCollectAwareVO> {

    @Autowired
    VariableParamService variableParamService;

    @Autowired
    VariableService variableService;

    @Autowired
    VarParamsCache varParamsCache;

    @Autowired
    VarMetaDataCache varMetaDataCache;


    @Override
    public void doHandle(VarContext<VarCollectAwareVO> context) {
        VarCollectAwareVO varCollectAwareVO = context.get();
        Set<String> varCodes = varCollectAwareVO.getVarCodes();
        Map<String, Object> executorResultMap = varCollectAwareVO.getExecutorResultMap();

        Optional<Map<String, Variable>> varsMetaDataCache = Optional.ofNullable(varMetaDataCache.loadVarMetaData());
        Optional<Map<String, Set<String>>> loadVarParamsCache = Optional.ofNullable(varParamsCache.loadVarParams());
        Map<String, Set<String>> derivedVarAndParamMap;
        if (varsMetaDataCache.isPresent() && loadVarParamsCache.isPresent()) {
            log.info("requestId = {} VarDeriveDependParamHandler 查询缓存 VarMetaDataCache & VarParamsCache ", JSONObject.toJSONString(varCollectAwareVO.getRequestId()));
            derivedVarAndParamMap = varsMetaDataCache.get()
                    .values()
                    .stream()
                    .filter(var -> varCodes.contains(var.getVarCode()))
                    .filter(var -> VariableEnum.DERIVE_VAR.getCode().equals(String.valueOf(var.getVarType())))
                    .collect(HashMap::new, (map, entry) -> map.put(entry.getVarCode(), loadVarParamsCache.get().get(entry.getVarCode())),
                            HashMap::putAll);
        } else {
            derivedVarAndParamMap =
                    Optional
                            .ofNullable(varCodes)
                            .orElse(Collections.emptySet())
                            .stream()
                            .filter(varCode -> variableService.checkVarIsDerive(varCode))
                            .collect(Collectors.toMap(Function.identity(), varcode -> variableParamService.getVarParamCode(varcode), (e1, e2) -> e1));
        }

        List<String> deriveDependParamsToFetch = Collections.emptyList();
        Collection unionVars = Collections.emptyList();
        if (MapUtils.isNotEmpty(derivedVarAndParamMap)) {
            deriveDependParamsToFetch = derivedVarAndParamMap.values()
                    .stream()
                    .filter(Objects::nonNull)
                    .flatMap(Collection::stream).filter(Objects::nonNull)
                    .filter(varCode -> !executorResultMap.containsKey(varCode))
                    .filter(Objects::nonNull)
                    .distinct().collect(Collectors.toList());

            unionVars = CollectionUtils.union(varCodes, deriveDependParamsToFetch);

            varCollectAwareVO.setDerivedVarDependParamMap(derivedVarAndParamMap);
            varCollectAwareVO.setVarCodes(new HashSet<String>(unionVars));
        }

        Map varCodeAndVarTypeMap;
        if (varsMetaDataCache.isPresent()) {
            log.info("requestId = {} VarDeriveDependParamHandler 查询缓存 VarMetaDataCache", JSONObject.toJSONString(varCollectAwareVO.getRequestId()));
            Collection finalUnionVars = unionVars;
            varCodeAndVarTypeMap = varsMetaDataCache.get().values()
                    .stream()
                    .filter(var -> finalUnionVars.contains(var.getVarCode()))
                    .collect(HashMap::new,
                            (map, entry) -> map.put(entry.getVarCode(), entry.getVarType()), HashMap::putAll);
        } else {
            varCodeAndVarTypeMap = variableService.findVarCodeAndVarTypeMap(unionVars);
        }
        log.info("requestId = {} deriveVarAndParamMap:{},deriveDependParams:{}, varCodeAndVarTypeMap:{}, unionVars:{}",
                varCollectAwareVO.getRequestId(),
                JSONObject.toJSONString(derivedVarAndParamMap),
                JSONObject.toJSONString(deriveDependParamsToFetch),
                JSONObject.toJSONString(varCodeAndVarTypeMap),
                JSONObject.toJSONString(unionVars));
        varCollectAwareVO.setVarCodeAndTypeMap(varCodeAndVarTypeMap);
        context.setContext(varCollectAwareVO);

    }
}
